package com.yupi.moonBI.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.yupi.moonBI.bimqConfig.BIMessageProducer;
import com.yupi.moonBI.common.ErrorCode;
import com.yupi.moonBI.constant.CommonConstant;
import com.yupi.moonBI.constant.ModelConstant;
import com.yupi.moonBI.exception.BusinessException;
import com.yupi.moonBI.exception.ThrowUtils;
import com.yupi.moonBI.manager.AIManager;
import com.yupi.moonBI.manager.RedisLimiterManager;
import com.yupi.moonBI.mapper.ChartMapper;
import com.yupi.moonBI.mapper.UserMapper;
import com.yupi.moonBI.model.dto.chart.ChartEsDTO;
import com.yupi.moonBI.model.dto.chart.ChartQueryRequest;
import com.yupi.moonBI.model.dto.chart.GenChartByAiRequest;
import com.yupi.moonBI.model.entity.Chart;
import com.yupi.moonBI.model.entity.User;
import com.yupi.moonBI.model.enums.ChartStatusEnum;
import com.yupi.moonBI.model.vo.BIResponse;
import com.yupi.moonBI.service.ChartService;
import com.yupi.moonBI.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yupi.moonBI.common.ErrorCode.NOT_FOUND_ERROR;
import static com.yupi.moonBI.constant.RedisConstant.*;

/**
 * 作者博客：<a href="https://blog.csdn.net/weixin_65935065">https://blog.csdn.net/weixin_65935065</a>
 * @author 苦行修士
 */
@Service
@Slf4j
public class ChartServiceImpl extends ServiceImpl<ChartMapper, Chart>
        implements ChartService {

    Gson gson = new Gson();

    @Resource
    private RedisLimiterManager redisLimiterManager;

    //引入我们新定义的线程池
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private BIMessageProducer biMessageProducer;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    //注入
    @Resource
    private ModelConstant modelConstant;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ChartMapper chartMapper;

    @Resource
    private AIManager aiManager;


    /**
     * 🐟AI智能分析
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @param loginUser
     * @return
     * @throws FileNotFoundException
     */
    @Override
    public BIResponse genChartByAiService(MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest, User loginUser) throws FileNotFoundException {

        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String chartType = genChartByAiRequest.getChartType();

        //文件校验
        vaildFile(multipartFile);

        long biModelID = modelConstant.getModelId();

        /**
         * 将分析需求转成代码——
         *
         * ——分析需求：
         *         分析网站用户的增长情况
         *         原始数据：
         *         日期，用户数
         *         1号，10
         *         2号，20
         *         3号，30
         */
        //String promote = AIManager.PRECONDITION + "分析需求 " + goal + " \n原始数据如下: " + cvsData + "\n生成图标的类型是: " + chartType;
        //构造用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        //拼接分析目标
        String userGoal = goal;
        if (StringUtils.isNotBlank(chartType)) {
            userGoal += "，请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据:").append("\n");
        //压缩后的数据
        // 将excel文件转换为csv文件
        String csvData = ExcelUtils.excelToCsv(multipartFile);
        // 将csv文件内容添加到userInput中
        userInput.append(csvData).append("\n");

        // 调用aiManager的doChart方法，传入biModelID和userInput
        String result = aiManager.doChart(biModelID, userInput.toString());

        // 将返回结果按"【【【【【"分割
        String[] splits = result.split("【【【【【");
        // 如果分割后的结果长度小于3，抛出异常
        if (splits.length < 3) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI 生成错误");
        }
        // 获取生成的图表和结果
        String genChart = splits[1].trim();
        String genResult = splits[2].trim();

        //插入到数据库
        Chart chart = new Chart();
        chart.setGoal(goal);
        chart.setChartData(csvData);
        chart.setName(name);
        chart.setChartType(chartType);
        chart.setGenChart(genChart);
        chart.setGenResult(genResult);
        chart.setUserId(loginUser.getId());
        int saveResult = chartMapper.insert(chart);
        ThrowUtils.throwIf(saveResult != 1, ErrorCode.SYSTEM_ERROR, "图表保存失败");

        // 创建BIResponse对象
        BIResponse biResponse = new BIResponse();
        // 设置生成的图表和结果
        biResponse.setGenChart(genChart);
        biResponse.setGenResult(genResult);
        biResponse.setChartId(chart.getId());
        return biResponse;
    }

    /**
     * 星火AI模型智能分析
     * @param multipartFile
     * @param genChartByAiRequest
     * @param loginUser
     * @return
     * @throws FileNotFoundException
     */
    @Override
    public BIResponse genChartBySparkAiService(MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest, User loginUser) throws FileNotFoundException {

        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String chartType = genChartByAiRequest.getChartType();
        Long userId = loginUser.getId();

        //文件校验
        vaildFile(multipartFile);

        long biModelID = modelConstant.getModelId();

        //压缩后的数据
        // 将excel文件转换为csv文件
        String csvData = ExcelUtils.excelToCsv(multipartFile);

        //分析对象 = 预设 + 分析需求（goal） + 原始数据（cvsData）+ 图表类型（chartType）
        String promote = AIManager.PRECONDITION + "分析需求 " + goal + " \n原始数据如下: " + csvData + "\n生成图标的类型是: " + chartType;
        String resultData = aiManager.sendMesToAISpark02(promote);
        log.info("AI 生成的信息: {}", resultData);
        String[] splits = resultData.split("【【【【【");
        ThrowUtils.throwIf(splits.length < 3, ErrorCode.SYSTEM_ERROR);
        String genChart = splits[1].trim();
        String genResult = splits[2].trim();

        //插入到数据库
        Chart chart = new Chart();
        chart.setGoal(goal);
        chart.setChartData(csvData);
        chart.setName(name);
        chart.setChartType(chartType);
        chart.setGenChart(genChart);
        chart.setGenResult(genResult);
        chart.setUserId(userId);
        int saveResult = chartMapper.insert(chart);
        ThrowUtils.throwIf(saveResult != 1, ErrorCode.SYSTEM_ERROR, "图表保存失败");

        // 创建BIResponse对象
        BIResponse biResponse = new BIResponse();
        // 设置生成的图表和结果
        biResponse.setGenChart(genChart);
        biResponse.setGenResult(genResult);
        biResponse.setChartId(chart.getId());
        //AI调用次数扣减
        genChartByAICount(userId);
        return biResponse;
    }

    /**
     * 智能分析（异步线程池）
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @return
     */
    @Override
    public BIResponse genChartByAiAsycnService(MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest, User loginUser) throws FileNotFoundException {

        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String chartType = genChartByAiRequest.getChartType();
        //文件校验
        vaildFile(multipartFile);
        long biModelID = modelConstant.getModelId();
        /**
         * 将分析需求转成代码——
         *
         * ——分析需求：
         *         分析网站用户的增长情况
         *         原始数据：
         *         日期，用户数
         *         1号，10
         *         2号，20
         *         3号，30
         */
        //构造用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        //拼接分析目标
        String userGoal = goal;
        if (StringUtils.isNotBlank(chartType)) {
            userGoal += "，请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据:").append("\n");
        //压缩后的数据
        // 将excel文件转换为csv文件
        String csvData = ExcelUtils.excelToCsv(multipartFile);
        // 将csv文件内容添加到userInput中
        userInput.append(csvData).append("\n");


        //将图表插入到数据库
        Chart chart = new Chart();
        chart.setGoal(goal);
        chart.setChartData(csvData);
        chart.setName(name);
        chart.setChartType(chartType);
        //插入图表时，还没生成结束，先去掉这两个
        //chart.setGenChart(genChart);
        //chart.setGenResult(genResult);
        //设置任务状态为等待中
        chart.setStatus(ChartStatusEnum.WAITING.getValue());
        chart.setUserId(loginUser.getId());
        int saveResult = chartMapper.insert(chart);
        ThrowUtils.throwIf(saveResult <= 0, ErrorCode.SYSTEM_ERROR, "图表保存失败");

        //在最终返回结果前提交一个任务
        //todo 建议：处理任务队列满了以后抛异常的情况
        CompletableFuture.runAsync(() -> {
            //先修改图表任务状态为“”执行中”。等执行成功后，修改为“已完成”、保存执行结果；执行失败后，状态修改为“失败”，记录任务失败信息。
            Chart updateChart = new Chart();
            updateChart.setId(chart.getId());
            updateChart.setStatus(ChartStatusEnum.RUNNING.getValue());
            int b = chartMapper.updateById(updateChart);
            if (b <= 0) {
                handleChartUpdateError(chart.getId(), "更新图表执行中状态失败");
                return;
            }

            // 调用AI,aiManager的doChart方法，传入biModelID和userInput
            String result = aiManager.doChart(biModelID, userInput.toString());

            // 将返回结果按"【【【【【"分割
            String[] splits = result.split("【【【【【");
            // 如果分割后的结果长度小于3，抛出异常
            if (splits.length < 3) {
                handleChartUpdateError(chart.getId(), "AI 生成错误");
            }
            // 获取生成的图表和结果
            String genChart = splits[1].trim();
            String genResult = splits[2].trim();
            Chart updateChartResult = new Chart();
            updateChartResult.setId(chart.getId());
            updateChartResult.setGenChart(genChart);
            updateChartResult.setGenResult(genResult);
            updateChartResult.setStatus(ChartStatusEnum.SUCCEED.getValue());
            int updateResult = chartMapper.updateById(updateChartResult);
            if (updateResult <= 0) {
                handleChartUpdateError(chart.getId(), "更新图表成功状态失败");
            }
        }, threadPoolExecutor);
        // 创建BIResponse对象
        BIResponse biResponse = new BIResponse();
        biResponse.setChartId(chart.getId());
        return biResponse;
    }

    /**
     * 智能分析（异步消息队列）
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @param loginUser
     * @return
     */
    @Override
    public BIResponse genChartByAiMQService(MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest, User loginUser) throws FileNotFoundException {

        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String chartType = genChartByAiRequest.getChartType();
        Long userId = loginUser.getId();
        //文件校验
        vaildFile(multipartFile);

        //构造用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        //拼接分析目标
        String userGoal = goal;
        if (StringUtils.isNotBlank(chartType)) {
            userGoal += "，请使用" + chartType;
        }
        //压缩后的数据
        // 将excel文件转换为csv文件
        String csvData = ExcelUtils.excelToCsv(multipartFile);
        // 将csv文件内容添加到userInput中
        userInput.append(csvData).append("\n");

        //将图表插入到数据库
        Chart chart = new Chart();
        chart.setGoal(goal);
        chart.setChartData(csvData);
        chart.setName(name);
        chart.setChartType(chartType);
        //设置任务状态为等待中
        chart.setStatus(ChartStatusEnum.WAITING.getValue());
        chart.setUserId(userId);
        int saveResult = chartMapper.insert(chart);
        ThrowUtils.throwIf(saveResult <= 0, ErrorCode.SYSTEM_ERROR, "图表保存失败");

        Long newChartId = chart.getId();
        biMessageProducer.sendMessage(String.valueOf(newChartId));
        // 创建BIResponse对象
        BIResponse biResponse = new BIResponse();
        biResponse.setChartId(chart.getId());
        return biResponse;
    }

    /**
     * 图表列表信息缓存
     *
     * @return
     */
    @Override
    public List<Chart> listChartByCacheService() {
        /**
         * 1、首先先从缓存中查询
         * 2、如果缓存中没有，则从数据库中获取，并放入缓存，如果缓存中存在，直接返回
         * 3、如果数据库中数据进行更新，那我们的缓存也要进行同步更新
         */
        //先从缓存中查询key是否存在,从缓存中获取key值
        Set<String> keys = stringRedisTemplate.keys(CHART_LIST_CACHE_KEY);
        //判断缓存是否为空，若不为空，则从缓存中获取key中的chart表json格式数据
        //判断keys和CHART_LIST_CACHE_KEY是否相等
        boolean equals = keys.contains(CHART_LIST_CACHE_KEY);
        if (equals) {
            //从缓存中获取key中的chart表json格式数据
            String chartjson = stringRedisTemplate.opsForValue().get(CHART_LIST_CACHE_KEY);

            //用于将JSON数据转换为Java对象
            List<Chart> chartList = JSONUtil.toList(chartjson, Chart.class);
            log.info("从缓存中获取chart表数据");
            return chartList;
        }
        //数据库中查询chartList数据
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        List<Chart> chartList02 = chartMapper.selectList(queryWrapper);
        //判断chartList02不为空
        if (chartList02 == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        //将数据库中的数据进行缓存
        //1、先将Java对象转换成json格式
        String cachechartjson = JSONUtil.toJsonStr(chartList02);
        //判断cachechartjson不为空
        if (cachechartjson == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        stringRedisTemplate.opsForValue().set(CHART_LIST_CACHE_KEY, cachechartjson
                , CHART_LIST_CACHE_TIME, TimeUnit.MINUTES);
        log.info("成功将chart表数据存入缓存中");
        return chartList02;
    }

    /**
     * 分页获取图表列表缓存信息
     * @param chartQueryRequest
     * @param request
     * @return
     */
    @Override
    public List<Chart> listChartByCachePage(ChartQueryRequest chartQueryRequest,
                                            HttpServletRequest request) {
        long pageNumber = chartQueryRequest.getCurrent();//当前页数
        long pageSize = chartQueryRequest.getPageSize();// 每一页的数量

        long startIndex = (pageNumber - 1) * pageSize;
        long endIndex = startIndex + pageSize - 1;
        Set<String> elements = stringRedisTemplate.opsForZSet().range(CHART_LIST_CHCHE_KEY, startIndex, endIndex);
        if (elements != null && elements.size() > 0) {
            // 使用map操作将每个字符串转换为Chart对象，并收集到List<Chart>中
            List<Chart> CacheChartList = elements.stream()
                    //将json字符串转换成chart对象
                    .map(Chart -> gson.fromJson(Chart, Chart.class)
                    ).collect(Collectors.toList());
            log.info("从缓存中获取chart表数据");
            return CacheChartList;
        }

        //数据库中查询chartList数据
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        List<Chart> chartList = chartMapper.selectList(queryWrapper);
        //判断chartList02不为空
        if (chartList == null) {
            log.error("图表列表信息不存在！！！");
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        for (int i = 0; i < chartList.size(); i++) {
            Chart chart = chartList.get(i);
            // 将chart对象转换为字符串，这里假设你有一个方法可以将Chart对象转换为JSON字符串
            String chartJson = gson.toJson(chart);
            // 将chartJson添加到ZSet中，分数为i
            stringRedisTemplate.opsForZSet().add(CHART_LIST_CHCHE_KEY, chartJson, i);
            log.info("chart图表数据导入成功,id:{}",chart.getId());
        }
        Page<Chart> chartPageList = this.page(new Page<>(pageNumber, pageSize), queryWrapper);
        log.info("chart图表数据导入成功,总条数:{}",chartList.size());
        return chartPageList.getRecords();
    }

    /**
     * 获取单个图表缓存
     *
     * @param id
     * @return
     */
    @Override
    public Chart getChartByIdCache(long id) {

        //判断id是否为空
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //拼接chartCacheId
        String chartCacheId = CHART_CHCHE_ID + id;
        //从redis中获取chartCacheData
        String chartCacheData = stringRedisTemplate.opsForValue().get(chartCacheId);
        //判断chartId不为空
        if (StrUtil.isNotBlank(chartCacheData)) {
            ////创建ObjectMapper对象
            //ObjectMapper objectMapper = new ObjectMapper();
            ////将chartCacheData转换成Chart对象
            //Chart chart = objectMapper.readValue(chartCacheData, Chart.class);
            Chart chart = JSONUtil.toBean(chartCacheData, Chart.class);
            //Chart chart = gson.fromJson(chartCacheData, Chart.class);
            //返回成功结果
            log.info("成功从Redis缓存中获取到数据，图表Key：{}",chartCacheId);
            return chart;
        }

        //根据id查询图表
        Chart chart = chartMapper.selectById(id);
        //判断图表是否为空
        if (chart == null) {
            throw new BusinessException(NOT_FOUND_ERROR);
        }
        //将图表转换成json字符串
        String chartDataJson = JSONUtil.toJsonStr(chart);
        //将图表缓存到redis中
        stringRedisTemplate.opsForValue().set(chartCacheId, chartDataJson, CHART_CACHE_TIME, TimeUnit.MINUTES);
        log.info("成功将图表缓存到Redis中，图表Key：{}",chartCacheId);
        return chart;
    }

    /**
     * ai调用次数统计
     *
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public Integer genChartByAICount(Long userId) {
        //判断chartId是否为空
        if (userId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"图表不存在！");
        }
        //根据用户ID查询用户并进行次数扣减
        //SQL语句：update user set count=count-1 where id = #{userId} and count > 0
        UpdateWrapper <User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",userId);
        updateWrapper.gt("number",0);
        updateWrapper.setSql("number=number-1");
        int updateResult = userMapper.update(null, updateWrapper);
        //判断更新结果
        if (updateResult != 1) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"AI调用次数扣减失败！");
        }
        return updateResult;
    }

    /**
     * es搜索图表数据
     *
     * @param chartQueryRequest
     * @return
     */
    @Override
    public Page<Chart> searchChartByEs(ChartQueryRequest chartQueryRequest) {
         Long id = chartQueryRequest.getId();
         String name = chartQueryRequest.getName();
         String goal = chartQueryRequest.getGoal();
         String chartType = chartQueryRequest.getChartType();
         String status = chartQueryRequest.getStatus();
         Long userId = chartQueryRequest.getUserId();
         long current = chartQueryRequest.getCurrent()-1;
         long pageSize = chartQueryRequest.getPageSize();
         String sortField = chartQueryRequest.getSortField();
         String sortOrder = chartQueryRequest.getSortOrder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 过滤
        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete", 0));
        if (id != null && id != 0) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("id", id));
        }
        if (StrUtil.isNotBlank(name)) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("name", name));
            //boolQueryBuilder.minimumShouldMatch(1);
        }
        if (StrUtil.isNotBlank(goal)) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("goal", goal));
            //boolQueryBuilder.minimumShouldMatch(1);
        }
        if (StrUtil.isNotBlank(chartType)) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("chartType", chartType));
            //boolQueryBuilder.minimumShouldMatch(1);
        }
        if (StrUtil.isNotBlank(status)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("status", status));
        }
        if (userId != null && userId != 0) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("userId", userId));
        }
        // 排序
        SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
        if (StringUtils.isNotBlank(sortField)) {
            sortBuilder = SortBuilders.fieldSort(sortField);
            sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC : SortOrder.DESC);
        }
        // 分页
        PageRequest pageRequest = PageRequest.of((int) current, (int) pageSize);
        // 构造查询
        // 创建一个NativeSearchQuery对象，用于执行Elasticsearch查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                // 设置查询条件
                .withPageable(pageRequest).withSorts(sortBuilder).build();
        // 使用elasticsearchRestTemplate执行查询，返回SearchHits对象
        SearchHits<ChartEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, ChartEsDTO.class);
        // 创建一个Page对象，用于存储查询结果
        Page<Chart> page = new Page<>();
        // 设置Page对象的总数
        page.setTotal(searchHits.getTotalHits());
        List<Chart> resourceList = new ArrayList<>();
        // 查出结果后，从 db 获取最新动态数据（比如点赞数）
        // 判断是否有搜索结果
        if (searchHits.hasSearchHits()) {
            // 获取搜索结果列表
            List<SearchHit<ChartEsDTO>> searchHitList = searchHits.getSearchHits();
            // 获取搜索结果中的 chartId 列表
            List<Long> chartIdList = searchHitList.stream().map(searchHit -> searchHit.getContent().getId())
                    .collect(Collectors.toList());
            // 根据 chartId 列表查询 chart 数据
            List<Chart> chartList = baseMapper.selectBatchIds(chartIdList);
            // 判断查询结果是否为空
            if (chartList != null) {
                // 将 chart 数据按 id 分组
                Map<Long, List<Chart>> idChartMap = chartList.stream().collect(Collectors.groupingBy(Chart::getId));
                // 遍历 chartId 列表
                chartIdList.forEach(chartId -> {
                    // 判断 idChartMap 中是否包含该 chartId
                    if (idChartMap.containsKey(chartId)) {
                        // 如果包含，则将对应的 chart 数据添加到 resourceList 中
                        resourceList.add(idChartMap.get(chartId).get(0));
                    } else {
                        // 如果不包含，则从 es 中删除该 chart 数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(chartId), ChartEsDTO.class);
                        log.info("删除图表 {}", delete);
                    }
                });
            }
        }
        page.setRecords(resourceList);
        return page;
    }


    /**
     * 校验文件
     *
     * @param multipartFile
     */
    private void vaildFile(MultipartFile multipartFile) {
        // 获取文件大小
        long size = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();

        //校验文件大小
        final long ONE_MB = 1024 * 1024L;
        ThrowUtils.throwIf(size > ONE_MB, ErrorCode.PARAMS_ERROR, "文件过大,超过1M");
        //校验文件后缀
        String suffix = FileUtil.getSuffix(originalFilename);
        final List<String> vaildFileSuffixList = Arrays.asList("png", "jpg", "jpeg", "svg", "webp", "xlsx");
        ThrowUtils.throwIf(!vaildFileSuffixList.contains(suffix), ErrorCode.PARAMS_ERROR, "文件后缀非法");
    }

    /**
     * 上面接口很多用到异常
     * 创建一个回调函数，对图表状态失败这一情况进行集中异常处理
     */
    private void handleChartUpdateError(long chartId, String execMessage) {
        Chart updateChartResult = new Chart();
        updateChartResult.setId(chartId);
        updateChartResult.setExecMessage("execMessage");
        updateChartResult.setStatus(ChartStatusEnum.FAILED.getValue());
        int updateResult = chartMapper.updateById(updateChartResult);
        if (updateResult <= 0) {
            log.error("更新图表失败状态失败" + chartId + "," + execMessage);
        }
    }
}




